import { director, ISchedulable, macro, Scheduler, System } from 'cc';

type UpdateCallback = (dt: number) => void;

interface UpdateTask {
    callback: UpdateCallback;
    priority: number;
    paused: boolean;
    once: boolean;
}

export class GlobalUpdateManager implements ISchedulable {
    id: string = '';
    uuid: string = '';
    update(dt: number) {
        console.log('self', dt);
    }

    private static _instance: GlobalUpdateManager;
    private _tasks: UpdateTask[] = [];

    private constructor() {}

    static get instance(): GlobalUpdateManager {
        if (!this._instance) {
            this._instance = new GlobalUpdateManager();
        }
        return this._instance;
    }

    enable() {
        Scheduler.enableForTarget(this);
        director
            .getScheduler()
            .schedule(
                this._update,
                this,
                0,
                macro.REPEAT_FOREVER,
                0,
                false,
            );
    }

    disable() {
        director.getScheduler().unschedule(this._update, this);
    }

    add(callback: UpdateCallback, priority = 0, once = false) {
        if (this._tasks.find((t) => t.callback === callback)) return;

        this._tasks.push({ callback, priority, paused: false, once });
        this._sortTasks();
    }

    remove(callback: UpdateCallback) {
        this._tasks = this._tasks.filter((t) => t.callback !== callback);
    }

    pause(callback: UpdateCallback) {
        const task = this._tasks.find((t) => t.callback === callback);
        if (task) task.paused = true;
    }

    resume(callback: UpdateCallback) {
        const task = this._tasks.find((t) => t.callback === callback);
        if (task) task.paused = false;
    }

    clear() {
        this._tasks.length = 0;
    }

    private _update(dt?: number) {
        for (let i = 0; i < this._tasks.length; i++) {
            const task = this._tasks[i];
            if (!task.paused) {
                task.callback(dt ?? 0);
                if (task.once) {
                    this._tasks.splice(i, 1);
                    i--;
                }
            }
        }
    }

    private _sortTasks() {
        this._tasks.sort((a, b) => b.priority - a.priority);
    }
}

//TEST
// setTimeout(() => {
//     GlobalUpdateManager.instance.add((dt) => {
//         console.log('High priority update', dt);
//     }, 10);

//     GlobalUpdateManager.instance.add(
//         (dt) => {
//             console.log('Run once');
//         },
//         0,
//         true,
//     );
// }, 10000);
